﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
using Model;

namespace Server
{
    public partial class MainForm : Form
    {
        /// <summary>保存连接的所有用户</summary>
        private readonly List<User> _userList = new List<User>();

        /// <summary>监听客户端连接</summary>
        private TcpListener _myListener;

        public MainForm()
        {
            InitializeComponent();
            string serverIp = ConfigurationManager.ConnectionStrings["serverIP"].ConnectionString;
            string serverPort = ConfigurationManager.ConnectionStrings["serverPort"].ConnectionString;
            StartServer(IPAddress.Parse(serverIp), int.Parse(serverPort));
            txtAddress.Text = serverIp;
            txtPort.Text = serverPort;
            AddTalkMessage(DateTime.Now + "： 开始监听客户连接");
            //创建一个线程监听客户端连接请求
            var myThread = new Thread(ListenClientConnect) { IsBackground = true };
            myThread.Start();
        }

        private void BtnSendMsgClick(object sender, EventArgs e)
        {
            ListBox.SelectedIndexCollection indexs = listChooseClient.SelectedIndices;
            string msg = txtSendMsg.Text;
            for (int i = 0; i < indexs.Count; i++)
            {
                int index = indexs[i];
                var userName = (string)listChooseClient.Items[index];
                User user = _userList.FirstOrDefault(s => s.Client.Client.RemoteEndPoint.ToString() == userName);
                if (user != null)
                {
                    SendToClient(user, 0);
                    SendToClient(user, msg, true);
                }
            }
        }

        private void MainFormFormClosing(object sender, FormClosingEventArgs e)
        {
            StopServer();
        }

        /// <summary>
        /// 开启服务器
        /// </summary>
        public void StartServer(IPAddress ip, int port)
        {
            _myListener = new TcpListener(ip, port);
            _myListener.Start();
        }

        /// <summary> 在txtMsg中追加聊天信息</summary>
        private void AddTalkMessage(string message)
        {
            try
            {
                if (txtMsg.InvokeRequired)
                {
                    MessageDelegate d = AddTalkMessage;
                    txtMsg.Invoke(d, new object[] { message });
                }
                else
                {
                    txtMsg.AppendText(message + Environment.NewLine);
                    txtMsg.ScrollToCaret();
                }
            }
            catch (Exception)
            {
                Application.Exit();
            }
        }

        /// <summary>接收客户端连接</summary>
        private void ListenClientConnect()
        {
            while (true)
            {
                TcpClient newClient;
                try
                {
                    newClient = _myListener.AcceptTcpClient();
                }
                catch
                {
                    //当单击“停止监听”或者退出此窗体时AcceptTcpClient()会产生异常
                    //因此可以利用此异常退出循环
                    break;
                }
                //每接受一个客户端连接,就创建一个对应的线程循环接收该客户端发来的信息
                var user = new User(newClient);
                var threadReceive = new Thread(ReceiveData);
                threadReceive.Start(user);
                string remoteEndPoint = newClient.Client.RemoteEndPoint.ToString();
                if (_userList.Count > 0)
                {
                    SendToClient(user, 2);
                    SendToClient(user, (short)_userList.Count);
                    foreach (User user1 in _userList)
                    {
                        SendToClient(user, user1.Client.Client.RemoteEndPoint.ToString(), false);

                        SendToClient(user1, 2);
                        SendToClient(user1, 1);
                        SendToClient(user1, remoteEndPoint, false);
                    }
                }
                _userList.Add(user);
                AddListUser(remoteEndPoint);
                ChangeConnectNum(_userList.Count + "");
                AddTalkMessage(string.Format("{0}： [{1}]进入", DateTime.Now.ToShortTimeString(),
                                             remoteEndPoint));
                SendToClient(user, 0);
                SendToClient(user, "Hello,I am server...", true);
            }
        }

        private void ChangeConnectNum(string connectNum)
        {
            if (labelConnectNum.InvokeRequired)
            {
                MessageDelegate d = ChangeConnectNum;
                labelConnectNum.Invoke(d, new object[] { connectNum });
            }
            else
            {
                labelConnectNum.Text = connectNum;
            }
        }

        private void AddListUser(string userName)
        {
            if (listChooseClient.InvokeRequired)
            {
                MessageDelegate d = AddListUser;
                listChooseClient.Invoke(d, new object[] { userName });
            }
            else
            {
                listChooseClient.Items.Add(userName);
            }
        }

        /// <summary>
        /// 处理接收的客户端数据
        /// </summary>
        /// <param name="userState">客户端信息</param>
        private void ReceiveData(object userState)
        {
            var user = (User)userState;
            string remoteEndPoint = user.Client.Client.RemoteEndPoint.ToString();
            while (true)
            {
                short receiveNum;
                try
                {
                    //从网络流中读出短整数，此方法会自动判断字符串长度前缀，并根据长度前缀读出字符串
                    receiveNum = user.Br.ReadInt16();
                }
                catch
                {
                    AddTalkMessage(string.Format("{0}： [{1}]已注销登录", DateTime.Now.ToShortTimeString(), remoteEndPoint));
                    RemoveListUser(remoteEndPoint);
                    RemoveUser(user);
                    foreach (User user1 in _userList)
                    {
                        SendToClient(user1, 3);
                        SendToClient(user1, remoteEndPoint, false);
                    }
                    ChangeConnectNum(_userList.Count + "");
                    break;
                }
                switch (receiveNum)
                {
                    //用户对服务器说
                    case 0:
                        AddTalkMessage(string.Format("{0}说：{1}",
                                                     remoteEndPoint, user.Br.ReadString()));
                        break;
                    //用户对用户说
                    case 1:
                        User talkUser = GetUserByRemotePoint(user.Br.ReadString());
                        string message = user.Br.ReadString();
                        SendToClient(talkUser, 1);
                        SendToClient(talkUser, remoteEndPoint, false);
                        SendToClient(talkUser, message, true);
                        AddTalkMessage(string.Format("{0}对{1}说：{2}",
                                                     remoteEndPoint, talkUser.Client.Client.RemoteEndPoint, message));
                        break;
                    default:
                        AddTalkMessage("什么意思啊：" + receiveNum);
                        break;
                }
            }
        }

        private User GetUserByRemotePoint(string remoteEndPoint)
        {
            return _userList.FirstOrDefault(m => m.Client.Client.RemoteEndPoint.ToString() == remoteEndPoint);
        }

        private void RemoveListUser(string remoteEndPoint)
        {
            if (listChooseClient.InvokeRequired)
            {
                MessageDelegate d = RemoveListUser;
                listChooseClient.Invoke(d, new object[] { remoteEndPoint });
            }
            else
            {
                for (int i = 0; i < listChooseClient.Items.Count; i++)
                {
                    object item = listChooseClient.Items[i];
                    if ((string)item != remoteEndPoint) continue;
                    listChooseClient.Items.Remove(item);
                    break;
                }
            }
        }

        /// <summary>
        /// 发送控制消息类型的短整数给用户
        /// </summary>
        /// <param name="user">指定发给哪个用户</param>
        /// <param name="controlNum">控制消息类型的短整数</param>
        private void SendToClient(User user, short controlNum)
        {
            try
            {
                //将字符串写入网络流，此方法会自动附加字符串长度前缀
                user.Bw.Write(controlNum);
                user.Bw.Flush();
            }
            catch
            {
                AddTalkMessage(string.Format("向[{0}]发送信息失败",
                                             user.Client.Client.RemoteEndPoint));
            }
        }

        /// <summary>
        /// 发送消息给用户
        /// </summary>
        /// <param name="user">指定发给哪个用户</param>
        /// <param name="message">信息内容</param>
        /// <param name="isTalk">是否将发送消息显示在服务器上</param>
        private void SendToClient(User user, string message, bool isTalk)
        {
            try
            {
                //将字符串写入网络流，此方法会自动附加字符串长度前缀
                user.Bw.Write(message);
                user.Bw.Flush();
                if (isTalk)
                {
                    AddTalkMessage(string.Format("向[{0}]发送：{1}",
                                                 user.Client.Client.RemoteEndPoint, message));
                }
            }
            catch
            {
                AddTalkMessage(string.Format("向[{0}]发送信息失败",
                                             user.Client.Client.RemoteEndPoint));
            }
        }

        /// <summary>移除用户</summary>
        /// <param name="user">指定要删除的用户</param>
        private void RemoveUser(User user)
        {
            _userList.Remove(user);
            user.Close();
        }

        /// <summary>
        /// 关闭服务器
        /// </summary>
        public void StopServer()
        {
            foreach (User user in _userList)
            {
                user.Close();
            }
            _myListener.Stop();
        }

        #region Nested type: MessageDelegate

        private delegate void MessageDelegate(string message);

        #endregion
    }
}